/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package minesweeper;

/**
 *
 * @author fanjun
 */
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import javax.swing.ImageIcon;
import javax.swing.Icon;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import javax.swing.Timer;
import javax.swing.JTextField;
import javax.swing.BorderFactory;
import javax.swing.KeyStroke;

/**
 *
 * @author fanjun
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        JFrame.setDefaultLookAndFeelDecorated(true);
        MainWindow frame = new MainWindow();
        frame.setResizable(false);//无法调整窗口大小
    }
}

class MainWindow extends JFrame implements ActionListener, MouseListener {

    JPanel panel = new JPanel();
    JLabel label = new JLabel("select the level:");
    String level[] = {"Beginner", "Intermediate", "Advanced"};
    JComboBox choice = new JComboBox(level);
    JButton start = new JButton();
    JButton mines[][];
    int flags[][];//标志是否插旗了
    JMenuBar mbr;
    JMenu menu;
    JMenu help;
    JMenuItem about;
    JMenuItem m1;
    JMenuItem mTip;
    OptionDialog levelDlg;
    Map oo;
    static boolean over;//标志游戏是否结束
    Timer time;
    JTextField tf_time;
    JTextField tf_restmine;
    String showtime = new String("000");

    MainWindow() {
        super("Minesweeper");
        mbr = new JMenuBar();
        menu = new JMenu("Option");
        help = new JMenu("Help");
        menu.setMnemonic('O');
        help.setMnemonic('H');
        mbr.add(menu);
        mbr.add(help);
        m1 = new JMenuItem("level", new ImageIcon("image//kenni.jpg"));
        m1.setAccelerator(KeyStroke.getKeyStroke("N"));
        about = new JMenuItem("about", new ImageIcon("image//eric.jpg"));
        about.setAccelerator(KeyStroke.getKeyStroke("A"));
        menu.add(m1);
        help.add(about);
        m1.addActionListener(this);
        mTip = new JMenuItem("Give me a tip", new ImageIcon("image//kare.jpg"));
        mTip.addActionListener(this);
        mTip.setAccelerator(KeyStroke.getKeyStroke("T"));
        mTip.setEnabled(false);
        help.add(mTip);
        about.addActionListener(this);
        setLayout(null);
        this.setJMenuBar(mbr);
        start.setText("<html><font color=\"#FF0080\"><em>Start</em></font></html>");
        start.addActionListener(this);
        start.setMnemonic('s');//快捷键设为ALT+S
        start.setBorder(BorderFactory.createRaisedBevelBorder());
        time = new Timer(1000, this);//添加计时器
        tf_time = new JTextField(3);
        tf_restmine = new JTextField(3);
        tf_time.setText(showtime);        
        tf_restmine.setText(Integer.toString(Record.restMine));
        tf_time.setBorder(BorderFactory.createLoweredBevelBorder());
        tf_restmine.setBorder(BorderFactory.createLoweredBevelBorder());
        tf_time.setHorizontalAlignment(JTextField.CENTER);
        tf_restmine.setHorizontalAlignment(JTextField.CENTER);   
        tf_time.setEditable(false);
        tf_restmine.setEditable(false);
        setLayout(new BorderLayout());
        JPanel pNorth = new JPanel();
        pNorth.add(tf_restmine);
        pNorth.add(start);
        pNorth.add(tf_time);
        add(pNorth, BorderLayout.NORTH);
        add(panel, BorderLayout.CENTER);
        setSize(20 * Record.col, 20 * Record.row + 90);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        setVisible(true);
    }

    boolean rangeRow(int a) {
        if (a >= 0 && a <= Record.row - 1) {
            return true;
        } else {
            return false;
        }
    }

    boolean rangeCol(int a) {
        if (a >= 0 && a <= Record.col - 1) {
            return true;
        } else {
            return false;
        }
    }

    private void f(int i, int j) {
        if (rangeRow(i) && rangeCol(j) && mines[i][j].isEnabled() && flags[i][j] == 0) {
            mines[i][j].setEnabled(false);
            Record.hasEnabledFalse++;
            if (oo.mark[i][j] != 0) {
                String colorstr = new String();
                switch (oo.mark[i][j]) {
                    case 1:
                        colorstr = "blue";
                        break;
                    case 2:
                        colorstr = "green";
                        break;
                    case 3:
                        colorstr = "red";
                        break;
                    default:
                        //凡是大于等于4者都用紫色
                        colorstr = "Purple";
                }
                String str = "<html><P align=left><font size=3 color=" + colorstr + ">";
                str += Integer.toString(oo.mark[i][j]);
                str += "</p></html>";
                mines[i][j].setText(str);
            }
            mines[i][j].updateUI();
            if (oo.mark[i][j] == 0) {
                f(i - 1, j);
                f(i + 1, j);
                f(i, j - 1);
                f(i, j + 1);
                f(i - 1, j - 1);
                f(i + 1, j + 1);
                f(i + 1, j - 1);
                f(i - 1, j + 1);
            }
        }
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == about) {
            JOptionPane.showConfirmDialog(this, "nrty in Auguest 2009", "About", JOptionPane.CLOSED_OPTION, JOptionPane.INFORMATION_MESSAGE, new ImageIcon("image//author.jpg"));
            return;
        }
        if (e.getSource() == m1) {
            levelDlg = new OptionDialog(this);
            levelDlg.setLocationRelativeTo(null);
            levelDlg.setTitle("Level");
            levelDlg.setVisible(true);
            // levelDlg.setResizable(false);
            levelDlg.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            return;
        }
        if (e.getSource() == start) {
            if (!mTip.isEnabled()) {
                mTip.setEnabled(true);
            }
            showtime = "000";//每次将字符串清零 加上timer计时器的值就是当前流过的时间
            this.tf_time.setText(showtime);
            time.start();
            panel.removeAll();
            //“恢复初值”
            Record.hasEnabledFalse = 0;
            Record.hasFlaged = 0;
            Record.restMine = Record.Nmines - Record.hasFlaged;
            Record.right = 0;
            tf_restmine.setText(Integer.toString(Record.restMine));
            over = false;
            panel.setLayout(new GridLayout(Record.row, Record.col));
            oo = new Map(Record.row, Record.col, Record.Nmines);
            oo.generateMine();
            oo.generateMark();
            mines = new JButton[Record.row][Record.col];
            flags = new int[Record.row][Record.col];//每次开始 flags都会被重新创建 “恢复初值”
            int i, j;
            for (i = 0; i < Record.row; i++) {
                for (j = 0; j < Record.col; j++) {
                    mines[i][j] = new JButton();
                    mines[i][j].setActionCommand(Integer.toString(j + Record.col * i));
                    mines[i][j].addActionListener(new LowListener(this));//其实可以仅仅把this作为参数
                    mines[i][j].addMouseListener(this);
                    panel.add(mines[i][j]);
                }
            }
            panel.updateUI();
            setSize(20 * Record.col, 20 * Record.row + 90);
            return;
        }
        if (e.getSource() == mTip) {
            int i, j;

            boolean ok = false;
            while (ok == false) {
                if (Record.hasEnabledFalse + Record.Nmines + Record.hasFlaged - Record.right != Record.row * Record.col) {
                    //如果没有展开的是这样的个体：“要么是插上了旗，要么是雷”，那就没有办法再给出tip了
                    //也即当Record.col*Record.row-Record.hasEnabledFalse==Record.Nmines + Record.hasFlaged - Record.right时结束tip
                    i = (int) (Math.random() * Record.row);
                    j = (int) (Math.random() * Record.col);
                    if (mines[i][j].isEnabled() && flags[i][j] == 0 && oo.has[i][j] == 0) {//如果没有展开、没有雷而且没有插旗
                        f(i, j);
                        panel.updateUI();
                        ok = true;
                    }
                } else {
                    JOptionPane.showConfirmDialog(null, "没有提示了啊。。。", "提示", JOptionPane.CLOSED_OPTION, JOptionPane.INFORMATION_MESSAGE);
                    break;
                }
            }
            /*  System.out.println();
            System.out.println("Record.Nmines:" + Record.Nmines);
            System.out.println("Record.hasEnabledFalse:" + Record.hasEnabledFalse);
            System.out.println("Record.hasFlaged:" + Record.hasFlaged);
            System.out.println("Record.right:" + Record.right);*/

            //游戏结束之四 通过mTip结束
            if (Record.hasFlaged == Record.Nmines && Record.hasEnabledFalse == Record.col * Record.row - Record.Nmines) {
                time.stop();
                JOptionPane.showConfirmDialog(null, "恭喜你找到了所有的雷。。。", "提示", JOptionPane.CLOSED_OPTION, JOptionPane.PLAIN_MESSAGE, new ImageIcon("image//laugh.jpg"));
                MainWindow.over = true;

            }
            return;

        }
        if (e.getSource() == time) {
            int len = tf_time.getText().length();
            int timenow = Integer.parseInt(tf_time.getText()) + 1;
            int lennow = Integer.toString(timenow).length();
            if (lennow < len) {
                String temp = new String();
                for (int i = 0; i < len - lennow; i++) {
                    temp += "0";
                }
                this.tf_time.setText(temp + Integer.toString(timenow));
            }
            return;
        }
    }

    public void mouseClicked(MouseEvent e) {
        if (over == false) {
            if (e.getModifiers() == InputEvent.BUTTON3_MASK) {
                int xx = panel.getWidth() / Record.col;//每个地雷的宽度
                int yy = panel.getHeight() / Record.row;//每个地雷的高度
                int y = (e.getLocationOnScreen().x - panel.getLocationOnScreen().x) / xx;
                int x = (e.getLocationOnScreen().y - panel.getLocationOnScreen().y) / yy;
                if (flags[x][y] == 0 && mines[x][y].isEnabled()) {//右键单击时 如果没有插过旗 则插上旗 。注意 已经展开的就不能再插旗了
                    Icon icon = new ImageIcon("image//flag.jpg");
                    mines[x][y].setIcon(icon);
                    flags[x][y] = 1;
                    if (oo.has[x][y] == 1) {
                        Record.right++;//插对了旗 插旗时对right的修改 当然去旗时也要修改right
                    }
                    Record.hasFlaged++;
                    Record.restMine--;
                    tf_restmine.setText("" + Record.restMine);
                }
                //游戏结束之一 右键单击结束 找到雷
                if (Record.hasFlaged == Record.Nmines && Record.hasEnabledFalse == Record.col * Record.row - Record.Nmines) {
                    time.stop();
                    JOptionPane.showConfirmDialog(null, "恭喜你找到了所有的雷。。。", "提示", JOptionPane.CLOSED_OPTION, JOptionPane.PLAIN_MESSAGE, new ImageIcon("image//laughgfw.jpg"));
                    over = true;

                }
            }
        }
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }
}

/**
 *自己写了一个类用于监听消息
 * button是对象，因此是引用，所以能判别mines是否被单击
 * 思想很重要 面向对象的思想 语言细节的运用 要细读thinking in java
 *
 */
class LowListener implements ActionListener {

    JButton button[][];
    int m;
    int n;
    Map oo1;
    JPanel p;
    int flags[][];
    Timer time;
    JTextField tf_restmine;

    LowListener(MainWindow fr) {
        // int i, j;
        this.m = Record.row;
        this.n = Record.col;
        this.oo1 = fr.oo;
        /* button = new JButton[m][n];
        for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
        button[i][j] = bt[i][j];
        }
        }*/
        this.button = fr.mines;//这样传递参数???引用型的变量这样传 button数组 不用写循环
        this.p = fr.panel;
        this.flags = fr.flags;
        this.time = fr.time;

        this.tf_restmine = fr.tf_restmine;

    }

    public void actionPerformed(ActionEvent e) {
        int i, j;
        int index = Integer.valueOf(e.getActionCommand());
        i = index / n;
        j = index % n;
        if (MainWindow.over == false) {//如果游戏未结束
            if (flags[i][j] == 0) {//该按钮没有插过旗
                if (oo1.mark[i][j] == -1) {//是雷
                    Icon icon = new ImageIcon("image//mines.jpg");
                    button[i][j].setIcon(icon);
                    //游戏结束之三 踩到雷
                    time.stop();
                    icon = new ImageIcon("image//cry.jpg");
                    JOptionPane.showConfirmDialog(null, "你踩到雷了,游戏结束。。。", "提示", JOptionPane.CLOSED_OPTION, JOptionPane.WARNING_MESSAGE, icon);
                    MainWindow.over = true;

                    int itemp, jtemp;
                    for (itemp = 0; itemp < Record.row; itemp++) {
                        for (jtemp = 0; jtemp < Record.col; jtemp++) {
                            if (oo1.has[itemp][jtemp] == 1 && flags[itemp][jtemp] == 0) {//如果是雷，却没有插上旗
                                Icon icontemp = new ImageIcon("image//mines.jpg");
                                button[itemp][jtemp].setIcon(icontemp);
                            } else if (oo1.has[itemp][jtemp] == 0 && flags[itemp][jtemp] == 1) {//如果不是雷，却插上了旗
                                Icon icontemp = new ImageIcon("image//error.jpg");
                                button[itemp][jtemp].setIcon(icontemp);
                            }
                        }
                    }
                    p.updateUI();
                } else {
                    f(i, j);
                    //游戏结束之二 左键单击结束 找到雷
                    if (Record.hasFlaged == Record.Nmines && Record.hasEnabledFalse == Record.col * Record.row - Record.Nmines) {
                        time.stop();
                        JOptionPane.showConfirmDialog(null, "恭喜你找到了所有的雷。。。", "提示", JOptionPane.CLOSED_OPTION, JOptionPane.PLAIN_MESSAGE, new ImageIcon("image//laugh.jpg"));
                        MainWindow.over = true;

                    }
                }
            } else {//该按钮已经插上旗
                button[i][j].setIcon(null);//把旗去掉
                flags[i][j] = 0;
                Record.hasFlaged--;
                Record.restMine++;
                if (oo1.has[i][j] == 1) {
                    Record.right--;
                }
                tf_restmine.setText("" + Record.restMine);
            }
        }
    }

    boolean rangeRow(int a) {
        if (a >= 0 && a <= Record.row - 1) {
            return true;
        } else {
            return false;
        }
    }

    boolean rangeCol(int a) {
        if (a >= 0 && a <= Record.col - 1) {
            return true;
        } else {
            return false;
        }
    }

    private void f(int i, int j) {
        if (rangeRow(i) && rangeCol(j) && button[i][j].isEnabled() && flags[i][j] == 0) {
            button[i][j].setEnabled(false);
            Record.hasEnabledFalse++;
            if (oo1.mark[i][j] != 0) {
                String colorstr = new String();
                switch (oo1.mark[i][j]) {
                    case 1:
                        colorstr = "blue";
                        break;
                    case 2:
                        colorstr = "green";
                        break;
                    case 3:
                        colorstr = "red";
                        break;
                    default:
                        //凡是大于等于4者都用紫色
                        colorstr = "Purple";
                }
                String str = "<html><P align=left><font size=3 color=" + colorstr + ">";
                str += Integer.toString(oo1.mark[i][j]);
                str += "</p></html>";
                button[i][j].setText(str);
            }
            button[i][j].updateUI();
            if (oo1.mark[i][j] == 0) {
                f(i - 1, j);
                f(i + 1, j);
                f(i, j - 1);
                f(i, j + 1);
                f(i - 1, j - 1);
                f(i + 1, j + 1);
                f(i + 1, j - 1);
                f(i - 1, j + 1);
            }
        }
    }
}

